using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightToolbox
{
    public class EventToAction : ControlExtenderBase
    {
        public EventToAction()
        {
            //System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("SilverlightCsharpLibraryTests.EventToAction.xaml");
            //this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());

            this.BaseLoaded += new EventHandler(EventToAction_Loaded);
        }

        void EventToAction_Loaded(object sender, EventArgs e)
        {
            Signup();
        }

        private void Signup()
        {
            if (IsPropertiesValid)
            {
                SignupForEventOnClass();
            }
        }

        private Canvas parent;
        private void SignupForEventOnClass()
        {
            foreach (DependencyObject control in ControlsToListen)
            {
                DoActualEventSignup(control, this.EventToListen);
                SignupForAllBooleanEvents(control);
            }
        }

        private void SignupForAllBooleanEvents(DependencyObject control)
        {
            foreach (PropertyInfo curPropertyInfoCheckIfIsEventToListenToAndSignupIfSo in this.GetType().GetProperties())
            {
                if (curPropertyInfoCheckIfIsEventToListenToAndSignupIfSo.Name.StartsWith("ListenTo"))
                {
                    bool propValue = (bool)curPropertyInfoCheckIfIsEventToListenToAndSignupIfSo.GetValue(this, null);
                    if (propValue)
                    {
                        string eventNameToSignUpTo =
                            curPropertyInfoCheckIfIsEventToListenToAndSignupIfSo.Name.Replace("ListenTo", "");
                        DoActualEventSignup(control, eventNameToSignUpTo);

                    }
                }
            }
        }




        private void DoActualEventSignup(DependencyObject control, string eventName)
        {
            if (!string.IsNullOrEmpty(eventName))
            {
                EventInfo signupTo = control.GetType().GetEvent(eventName);
                if (signupTo != null)
                {
                    AddEventHandler(control, signupTo);
                }
            }
        }

        private void AddEventHandler(DependencyObject control, EventInfo signupTo)
        {
            Delegate delegateToRunOnEventInvoke =
                Delegate.CreateDelegate(signupTo.EventHandlerType, this, this.GetType().GetMethod("RunActionOnTargetElement"));

            signupTo.AddEventHandler(control, delegateToRunOnEventInvoke);
        }

        public void RunActionOnTargetElement(object sender, EventArgs e)
        {
            foreach (DependencyObject targetElement in TargetsElement)
            {
                InvokeMethodOnTerget(targetElement, this.TargetAction, sender, e);
                RunActionsOnTargetElementBasedOnBooleanProperties(targetElement, sender, e);
            }
        }

        private void RunActionsOnTargetElementBasedOnBooleanProperties(DependencyObject targetElement, object sender, EventArgs e)
        {
            foreach (PropertyInfo curPropertyInfoCheckIfIsActivateAndInvokeIfSo in this.GetType().GetProperties())
            {
                if (curPropertyInfoCheckIfIsActivateAndInvokeIfSo.Name.StartsWith("Target")
                    && curPropertyInfoCheckIfIsActivateAndInvokeIfSo.PropertyType == typeof(bool))
                {
                    bool propValue = (bool)curPropertyInfoCheckIfIsActivateAndInvokeIfSo.GetValue(this, null);
                    if (propValue)
                    {
                        string methodNameToRun =
                            curPropertyInfoCheckIfIsActivateAndInvokeIfSo.Name.Replace("Target", "");
                        InvokeMethodOnTerget(targetElement, methodNameToRun, sender, e);

                    }
                }
            }
        }

        private void InvokeMethodOnTerget(DependencyObject sb, string methodNameToInvoke, object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(methodNameToInvoke))
            {
                MethodInfo methodInfoToInvoke = sb.GetType().GetMethod(methodNameToInvoke);
                if (methodInfoToInvoke == null)
                {
                    PropertyInfo propertyThatWeMightNeedToInvoke = sb.GetType().GetProperty(methodNameToInvoke);
                    if (propertyThatWeMightNeedToInvoke != null)
                    {
                        methodInfoToInvoke = propertyThatWeMightNeedToInvoke.GetSetMethod();
                    }
                }
                if (methodInfoToInvoke != null)
                {
                    methodInfoToInvoke.Invoke(sb, GetInvocationListParamterSBasedOnArgumentsAnd(methodInfoToInvoke, sender, e));
                }
            }
        }

        private object[] GetInvocationListParamterSBasedOnArgumentsAnd(MethodInfo methodInfoToInvoke, object sender, EventArgs e)
        {
            ArrayList ReturnValue = new ArrayList();

            if (!string.IsNullOrEmpty(TargetActionArguments))
                foreach (string paramName in this.TargetActionArguments.Replace(" ", "").Split(','))
                {
                    if (paramName == "sender")
                        ReturnValue.Add(sender);
                    else
                    {
                        PropertyInfo propInfo = e.GetType().GetProperty(paramName);
                        if (propInfo != null)
                        {
                            object PropValue = propInfo.GetValue(e, new object[] {});
                            if (methodInfoToInvoke.GetParameters()[ReturnValue.Count].ParameterType == typeof(string))
                            {
                                PropValue = PropValue.ToString();
                            }
                            if (methodInfoToInvoke.GetParameters()[ReturnValue.Count].ParameterType == typeof(Double))
                            {
                                PropValue = Convert.ToDouble(PropValue);
                            }
                            ReturnValue.Add(PropValue);
                        }
                        else
                            ReturnValue.Add(paramName);
                    }

                }

            return ReturnValue.ToArray();
        }

        private bool IsPropertiesValid
        {
            get
            {
                return ControlsToListen.Count > 0
                       && TargetsElement.Count > 0;
            }
        }

        private List<DependencyObject> _controlsToListen = new List<DependencyObject>();
        [FillXamlElementssByName("ElementsToListenName")]
        internal List<DependencyObject> ControlsToListen
        {
            get
            {
                return _controlsToListen;
            }
            set
            {
                _controlsToListen = value;
            }
        }

        public string ElementsToListenName
        {
            get;
            set;
        }

        public string EventToListen
        {
            get;
            set;
        }

        public string Target_Name
        {
            get;
            set;
        }

        private List<DependencyObject> _targetsElement = new List<DependencyObject>();
        [FillXamlElementssByName("Target_Name")]
        internal List<DependencyObject> TargetsElement
        {
            get
            {
                return _targetsElement;
            }
            set
            {
                _targetsElement = value;
            }
        }

        public string TargetAction
        {
            get;
            set;
        }

        public bool ListenToMouseEnter
        {
            get;
            set;
        }

        public bool ListenToMouseLeave
        {
            get;
            set;
        }

        public bool ListenToMouseLeftButtonDown
        {
            get;
            set;
        }

        public bool ListenToMouseLeftButtonUp
        {
            get;
            set;
        }

        public bool ListenToMouseMove
        {
            get;
            set;
        }


        public bool ListenToGotFocus
        {
            get;
            set;
        }

        public bool ListenToLostFocus
        {
            get;
            set;
        }

        public bool ListenToKeyDown
        {
            get;
            set;
        }

        public bool ListenToKeyUp
        {
            get;
            set;
        }

        //public bool ListenToLoaded
        //{
        //    get;
        //    set;
        //}

        public bool ListenToCompleted
        {
            get;
            set;
        }

        public string TargetActionArguments
        {
            get;
            set;
        }

        public bool TargetBegin
        {
            get;
            set;
        }

        public bool TargetStop
        {
            get;
            set;
        }

        public bool TargetPause
        {
            get;
            set;
        }

        public bool TargetResume
        {
            get;
            set;
        }
    }
}